<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
	<head>
		<meta charset="utf-8"/>
		<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
		<title>Функциональное программирование на языке Python</title>

		<link rel="stylesheet" type="text/css" href="http://moodle.spb.ru/file.php/84/python/standby.css"/><!-- page style: default -->
	</head>
	<body>
		<div class="page">
			<h2>Функциональное программирование</h2>
			<p>
				В этом уроке будут более подробно рассмотрены функции, их описание (объявление) и использование, будет рассмотрено такое понятие как рекурсия, передача и возврат функции в качестве аргументов, обработка последовательностей и итераторы, а также такое понятие как генератор.
			</p>
			<p>
				<span class="important" title="Определение"><b>Функциональное программирование</b> - это стиль программирования, использующий только <a href="http://ru.wikipedia.org/wiki/Композиция_функций" title="Посмотреть в ВИКИ">композиции функций</a></span>. Грубо говоря, здесь не используется последовательное выполнение команд, свойственное императивным и объектно-ориентированным языкам. Вместо этого комбинируются функции - результат выполнения одной функции используется в качестве аргумента для другой.
			</p>
			<p>
				Поддержка парадигмы функционального программирования накладывает ряд требований к языку и самому программисту. Приведённые ниже требования* сформулировал автор <a href="http://gnosis.cx/publish/programming/charming_python_13.txt" title="Посмотреть оригинальный текст">статьи</a>, посвящённой функциональному программированию на языке Python, Дэвид Мертц (David Mertz):
			</p>
			<p>
				<ul type="circle">
					<li>Функции - объекты первого класса. То есть, всё, что можно делать с "данными", можно делать и с функциями (вроде передачи функции другой функции в качестве параметра).</li>
					<li>Частое использование рекурсии. Использование рекурсии вместо обычных циклов (в некоторых функциональных языках привычных нам циклов нет вообще).</li>
					<li>Акцент на обработке списков (<i>lists</i>, отсюда название языка <a href="http://ru.wikipedia.org/wiki/Lisp" title="Посмотреть в ВИКИ">Lisp</a> - <i>LISt Processing</i> - обработка списков). Списки с рекурсивным обходом подсписков часто используются в качестве замены циклов.</li>
					<li>Полный отказ от всевозможных присваиваний или очень редкое их использование.</li>
					<li>Замена всех операторов вызовами функции. Например, знакомый вам <cite>if</cite> будет является функцией.</li>
					<li>Акцент делается на том, <b>что</b> должно быть вычислено, а не <b>как</b>.</li>
					<li>По большей части используются функции <a href="http://ru.wikipedia.org/wiki/Функция_высшего_порядка" title="Посмотреть в ВИКИ">высшего порядка</a> (функции, оперирующие функциями, оперирующими функциями,..).</li>
				</ul>
			</p>
			<div class="note">
				<p>
					Данные требования не что иное, как попытка описать, что из себя представляет функциональное программирование и функциональный язык в целом. Дело в том, что все функциональные языки можно условно разделить на два типа - чисто функциональные и гибридные. Чисто функциональным языком является, например, <a href="http://ru.wikipedia.org/wiki/Haskell" title="Посмотреть в ВИКИ">Haskell</a>. Гибридные языки содержат свойства как функциональных, так и императивных языков. Яркий пример - язык <a href="http://ru.wikipedia.org/wiki/Nemerle" title="Посмотреть в ВИКИ">Nemerle</a>.
				</p>
			</div>
			<h3>Функции как объекты</h3>
			<p>
				В языке Python всё является объектами - строка, число, <cite>True</cite>, <cite>None</cite>, списки и другие последовательности. И функции не являются исключением. Объявляя новую функцию, по сути, мы создаём новый объект. Это позволяет, например, связать с произвольным именем-идентификатором имя уже объявленной функции:
				<code>
					<span class="comment"># У нас есть функция, которая "здоровается" с нами:</span><br/><span style="color: #0000FF;">def</span><span style="color: #000000;"> func():</span><br/>&nbsp;&nbsp;&nbsp;&nbsp;print<span style="color: #000000;">('Hello, I'm a func')<br/>func()</span><br/><span class="comment"># Hello, I'm a func</span><br/><br/><span style="color: #000000;">f </span><span style="color: #000000;">=</span><span style="color: #000000;"> func<br/></span>print<span style="color: #000000;">(type(f))</span><br/><span class="comment"># &lt;class 'function'&gt;</span><br/><br/><span style="color: #000000;">f()</span><br/><span class="comment"># Hello, I'm a func</span>
				</code>
			</p>
			<p>
				Возможно, это не имеет особого смысла, но тут нам открывается ещё один пример использования функции как объекта, а именно передача функции в качестве аргумента и возврат функции в качестве результата. И тот и другой случай будут рассмотрены далее в этом уроке.
			</p>
			<p>
				Другим признаком того, что функция является объектом, можно назвать большое количество принадлежащих ей атрибутов. Попробуйте выполнить следующий код:
				<code>
					func.__name__<br/><span style="color: #000000;">dir(func)</span>
				</code>
			</p>
			<p>
				Первая строка кода после выполнения выведет имя функции, а вторая покажет полный список её атрибутов.
			</p>
			<h3>
				<b>&lambda;</b>-выражения
			</h3>
			<p>
				Мы уже говорили о функциях. Мы выяснили, как можно объявить функцию, какие можно задавать аргументы для неё (напомним, что можно использовать обычные аргументы, аргументы по-умолчанию, произвольное число аргументов и именованные аргументы). Мы так же выяснили, как можно из функции вернуть значение в качестве результата.
			</p>
			<p>
				Как вы уже знаете, определить функцию в Python можно двумя способами: с помощью оператора <cite>def</cite>, с которым вы уже познакомились, и <span class="important"><a href="http://ru.wikipedia.org/wiki/Лямбда-исчисление" title="Посмотреть в ВИКИ">lambda</a>-выражения</span>. Первый способ позволяет использовать в теле функции различные операторы (ветвления, циклы и прочие), <span class="important">при использовании второго способа можно использовать только выражения</span>.
			</p>
			<p>
				lambda-выражения ещё называют <i>безымянными</i> или <i>анонимными</i> функциями, поскольку при их определении не указывается конкретное имя-идентификатор. Синтаксис lambda-выражения выглядит следующим образом:
				<code>
					<span style="color: #0000FF;">lambda</span><span style="color: #000000;"> [список аргументов] : выражение</span>
				</code>
			</p>
			<p>
				<span class="important">lambda-выражения обладают всеми свойствами функций</span>. Это значит, что можно использовать различные виды аргументов при объявлении, оперировать lambda-выражением как объектом или значением. Например:
				<code>
					<span style="color: #000000;">func </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">lambda</span><span style="color: #000000;"> x, y : x </span><span style="color: #000000;">+</span><span style="color: #000000;"> y</span>
				</code>
			</p>
			<p>
				Функция, записанная с помощью lambda-выражения, получает в качестве аргументов два значения, а на выходе мы получаем их сумму. Первое, на что стоит обратить внимание - здесь мы ничего не вычисляем, а только <b>объявляем</b> новую функцию. Далее, если посмотреть значение атрибута <cite>__name__</cite> у объекта, связанного с <cite>func</cite>, оно выведет строку вида <cite>'&lt;lambda&gt;'</cite>, поскольку, как уже говорилось ранее, lambda-выражения - это безымянные функции:
				<code>
					<span style="color: #000000;">func.</span>__name__<span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;# Выведет '&lt;lambda&gt;'</span><br/><span style="color: #000000;">dir(func)</span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# Объекты для def и lambda функций идентичны</span>
				</code>
			</p>
			<p>
				После того, как мы связали lambda-выражение c именем <cite>func</cite>, мы можем его использовать для вызова этой функции:
				<code>
					<span style="color: #000000;">func(3, 4)</span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# 7</span>
				</code>
			</p>
			<h3>
				Рекурсия
			</h3>
			<p>
				<span class="important" title="Определение">Рекурсией называется приём, при котором функция при выполнении вызывает саму себя</span>. Некоторые алгоритмы лучше (короче, элегантнее) реализуются с помощью рекурсии, и, если говорить о функциональных языках, она вообще используется чаще, чем <i>итерация</i> (циклы).
			</p>
			<p>
				Наверняка, вы уже сталкивались с этим понятием на курсах по другим языкам программирования, поэтому мы не будем подробно разбирать разновидности рекурсии и другие особенности этого приёма. Но мы, всё же, напомним, что не стоит гнаться за красивым рекурсивным решением в ущерб производительности. В этом плане <u>плохим</u> примером является рекурсивный вариант нахождения n-го <a href="http://ru.wikipedia.org/wiki/Числа_Фибоначчи" title="Посмотерть в ВИКИ">числа</a> Фибоначчи:
				<code>
					<span style="color: #0000FF;">def</span><span style="color: #000000;"> Fib(n) :</br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF;">if</span><span style="color: #000000;"> n </span><span style="color: #000000;">&lt;</span><span style="color: #000000;"> </span><span style="color: #000000;">2</span><span style="color: #000000;"> :<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF;">return</span><span style="color: #000000;"> n<br/>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF;">else</span><span style="color: #000000;"> :<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF;">return</span><span style="color: #000000;"> Fib(n</span><span style="color: #000000;">-</span><span style="color: #000000;">1</span><span style="color: #000000;">) </span><span style="color: #000000;">+</span><span style="color: #000000;"> Fib(n </span><span style="color: #000000;">-</span><span style="color: #000000;"> </span><span style="color: #000000;">2</span><span style="color: #000000;">)</span>
				</code>
			</p>
			<p>
				В данном примере количество вызовов функции <cite>Fib</cite> пропорционально <cite>e^x</cite>, то есть на лицо экспоненциальная зависимость, а это не соответствует временной сложности задачи - она должна быть линейной.
			</p>
			<p>
				Стоит также отметить, что при использовании рекурсии стоит особое внимание уделять глубине рекурсии, числу вызовов функции самой себя. В Python'е, как и в других языках, существует предел глубины рекурсии. Если какой-либо функцией он будет достигнут, то тогда программа аварийно завершится с ошибкой.
			</p>
			<h3>Функции как результат</h3>
			<p>
				<span class="important">Функции - это объекты</span>. Значит, логично было бы предположить, что функцию можно вернуть в качестве результата работы другой функции, ведь возможно же вернуть целое число, список или словарь из функции. Это действительно возможно. Рассмотрим такой пример:
				<code>
					<span style="color: #0000FF;">def</span><span style="color: #000000;"> getMultiplier(n):<br/>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF;">def</span><span style="color: #000000;"> multiplier(m):<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF;">return</span><span style="color: #000000;"> n </span><span style="color: #000000;">*</span><span style="color: #000000;"> m<br/>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF;">return</span><span style="color: #000000;"> multiplier<br/><br/>mult2 </span><span style="color: #000000;">=</span><span style="color: #000000;"> getMultiplier(</span><span style="color: #000000;">2</span><span style="color: #000000;">)<br/></span>print<span style="color: #000000;">(mult2(</span><span style="color: #000000;">3</span><span style="color: #000000;">))<span class="comment"> # 9</span><br/></span>print<span style="color: #000000;">(mult2(</span><span style="color: #000000;">9</span><span style="color: #000000;">))<span class="comment"> # 18</span><br/><br/>mult5 </span><span style="color: #000000;">=</span><span style="color: #000000;"> getMultiplier(</span><span style="color: #000000;">5</span><span style="color: #000000;">)<br/></span>print<span style="color: #000000;">(mult(</span><span style="color: #000000;">3</span><span style="color: #000000;">))<span class="comment">&nbsp; # 15</span><br/></span>print<span style="color: #000000;">(mult(</span><span style="color: #000000;">9</span><span style="color: #000000;">))<span class="comment">&nbsp; # 45</span></span>
				</code>
			</p>
			<p>
				Функция <cite>getMultiplier</cite> возвращает функцию <cite>multiplier</cite>, которая умножает переданное ей число на число, переданное в <cite>getMultiplier</cite>. Данный пример, конечно, наигран, и в реальности умножение на n, вряд ли, кто-нибудь будет делать именно так, когда можно просто записать m * n. Но если нужно производить очень много операций, различающихся только параметрами, такой механизм становится очень эффективным.
			</p>
			<h3>Функции как параметры</h3>
			<p>
				Мы выяснили, что <span class="important">в Python мы можем возвращать функцию в качестве результата</span>. Но, помимо этого, <span class="important">мы также можем передавать функцию в качестве аргумента при вызове другой функции</span>. На самом деле, и в языке C тоже есть такая возможность.
			</p>
			<p>
				Зачем это может понадобится? Типичным примером использования этой возможности является реализация функции для сортировки массива данных с неизвестным типом элементов. Данной функции на вход передаётся сортируемый массив и имя функции, сравнивающей два однотипных элемента этого массива. Получается, что, благодаря этому приёму, функция сортировки становится, грубо говоря, универсальной, и она будет переставлять элементы в массиве по заданному правилу <i>(не обязательно от меньшего к большему)</i>:
				<code>
					<span style="color: #000000;">l = [(1,6), (2,4), (3,1), (4,-10), (5,5)]<span><br/><span class="comment"># Предположим, что нам нужно отсортировать данный список кортежей</span><br/><span class="comment"># не по нулевому элементу, а по первому</span>
				</code>
			</p>
			<p>
				Трудно выполнимая задача? Только не для Python! Функция <cite>sort</cite> у списков может принимать в качестве аргумента (имя аргумента - <cite>key</cite>) другую функцию, которая "говорит" <cite>sort</cite>, <u>что</u> нужно сравнивать. Рассмотрим два примера:
				<code>
					<span class="comment"># Без использования lambda-выражения:</span><br/><span style="color: #0000FF;">def</span><span style="color: #000000;"> cmp(t):<br/>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF;">return</span><span style="color: #000000;"> t[</span><span style="color: #000000;">1</span><span style="color: #000000;">]</span><br/><br/><span style="color: #000000;">l.sort(key</span><span style="color: #000000;"> = </span><span style="color: #000000;">cmp)<br/></span>print<span style="color: #000000;">(l)</span><br/><span class="comment"># [(4, -10), (3, 1), (2, 4), (5, 5), (1, 6)]</span><br/><br/><span class="comment"># С помощью lambda-выражения:</span><br/><span style="color: #000000;">l.sort(key</span><span style="color: #000000;"> = </span><span style="color: #0000FF;">lambda</span><span style="color: #000000;"> t : t[</span><span style="color: #000000;">1</span><span style="color: #000000;">])<br/></span>print<span style="color: #000000;">(l)</span><br/><span class="comment"># [(4, -10), (3, 1), (2, 4), (5, 5), (1, 6)]</span>
				</code>
			</p>
			<p>
				Функция <cite>sort</cite> передает каждый элемент списка в функцию <cite>key</cite> (если мы указали) и должна получить ключ, который используется для дальнейшей сортировки. Конечно, <cite>key</cite> может возвращать что-нибудь и не связанное с переданным ей элементом (например, число 1), но тогда теряется весь смысл сортировки.
			</p>
			<p>
				Как видите, запись с lambda-выражением смотрится гораздо лучше. Текст занимает меньше места, и в коде не образовывается совершенно непонятно для чего использующаяся функция <cite>cmp</cite>.
			</p><br/>
			<p>
				Существуют и другие примеры использования данной возможности. Так мы можем применять <u>любую</u> функцию-обработчик ко всем элементам какой-либо последовательности. Для этого существует специальная функция <cite><b>map(f, *args)</b></cite>.
			</p>
			<p>
				Первый аргумент у этой функции - имя другой функции или lambda-выражение. За ним идут остальные аргументы-последовательности - их количество и порядок соответствуют количеству и порядку аргументов переданной функции. Функция <cite>map</cite> берёт из каждой последовательности по элементу, отправляет их полученной функции, а результат записывает в новый список, который потом возвращает в качестве результата. Следующий пример складывает два списка поэлементно:
				<code>
					<span style="color: #000000;">l1 = [-5, 4, 37, -15, 2]<br/>l2 = [7, -2, -35, 17, 0]</span><br/><br/><span style="color: #000000;">result </span><span style="color: #000000;">=</span><span style="color: #000000;"> list(map(</span><span style="color: #0000FF;">lambda</span><span style="color: #000000;"> x, y : x </span><span style="color: #000000;">+</span><span style="color: #000000;"> y, l1, l2))</span><br/>print<span style="color: #000000;">(result)</span><br/><span class="comment"># [2, 2, 2, 2, 2]</span>
				</code>
			</p>
			<p>
				Если одна из последовательностей короче или длиннее остальных, недостающие элементы будут заменятся на <cite>None</cite>, после чего всё будет зависеть от переданной функции - можно обрабатывать ошибку или её игнорировать.
			</p>
			<p>
				Можно передать вместо имени функции или lambda-выражения значение <cite>None</cite>. Тогда сформируется список кортежей из элементов исходных последовательностей:
				<code>
					<span style="color: #000000;">l1 = [0, 1, 2, 3, 4]<br/>l2 = [5, 6, 7, 8, 9]</span><br/><br/><span style="color: #000000;">result </span><span style="color: #000000;">=</span><span style="color: #000000;"> list(map(None, l1, l2))</span><br/>print<span style="color: #000000;">(result)</span><br/><span class="comment"># [(0, 5), (1, 6), (2, 7), (3, 8), (4, 9)]</span>
				</code>
			</p><br/>
			<p>
				Более простой пример передачи функции в качестве аргумента - фильтр для последовательности. Функция так и называется - <cite><b>filter(f, s)</b></cite>. Её аргументами являются, во-первых, функция фильтрации, а во-вторых, фильтруемая последовательность. Для каждого элемента этой последовательности вызывается переданная функция, и, если она вернёт значение <cite>True</cite>, данный элемент признаётся валидным (годным) и попадает в результат.
			</p>
			<p>
				Например, можно из последовательности удалить все отрицательные элементы:
				<code>
					<span style="color: #000000;">l = [-1, 2, -4, 6, 7, -5, 8]</span><br/><br/><span style="color: #000000;">result </span><span style="color: #000000;">=</span><span style="color: #000000;"> list(filter(</span><span style="color: #0000FF;">lambda</span><span style="color: #000000;"> x : x </span><span style="color: #000000;">&gt;=</span><span style="color: #000000;"> 0, l))<br/></span>print<span style="color: #000000;">(result)</span><br/><span class="comment"># [2, 6, 7, 8]</span>
				</code>
			</p>
			<p>
				Если вместо функции передавать <cite>None</cite>, то <cite>filter()</cite> попытается привести тип каждого элемента к типу <cite>bool</cite>, и, если значение будет истинным, он попадёт в результат.
			</p>
			<h3>Итераторы</h3>
			<p>
				Возможно, вы заметили, что результат выполнения таких функций, как <cite>map()</cite> и <cite>filter()</cite> мы явно преобразовывали в список, чтобы вывести его на экран. Дело в том, что эти функции возвращают особые последовательности - <b>итераторы</b>.
			</p>
			<p>
				<span class="important" title="Определение">Итератор - это специальный объект, обеспечивающий последовательный доступ к данным</span>. В некоторых случаях работа с итераторами безопаснее, быстрее и эффективнее, чем, непосредственно, с самими контейнерами-последовательностями. Например, используя итератор для списка можно без проблем добавлять в него элементы. Если бы мы использовали произвольный доступ по индексу, у нас появилась бы проблема, так как индексация изменилась бы после добавления элементов. Так как итератор предлагает последовательный доступ, мы можем без проблем удалять и добавлять элементы в искомую последовательность во время обхода.
			</p>
			<p>
				Здесь стоит вспомнить о цикле <cite>for<cite>, который <u>по-умолчанию</u> создаёт именно итератор из используемой последовательности. Функция <cite>range()</cite>, кстати, о которой мы говорили ранее, также возвращает объект-итератор:
				<code>
					<span class="comment"># Если написать</span><br/><span style="color: #0000FF;">for</span><span style="color: #000000;"> i </span><span style="color: #0000FF;">in</span><span style="color: #000000;"> </span><span style="color: #000000;">1</span><span style="color: #000000;">:<br/>&nbsp;&nbsp;&nbsp;&nbsp;</span>print<span style="color: #000000;">(i)</span><br/><br/><span class="comment"># И запустить код, то интерпретатор выведет ошибку:</span><br/><span class="error"># TypeError: 'int' object is not iterable</span><br/><span class="comment"># Нельзя для целого числа создать итератор</span>
				</code>
			</p>
			<p>
				Чтобы создать итератор для последовательности, можно воспользоваться специальной функцией <cite>iter()</cite>. В качестве параметра в неё передаётся последовательность. После этого с полученным итератором можно работать вручную, используя метод <cite>__next__()</cite> для получения очередного элемента:
				<code>
					<span style="color: #000000;">l </span><span style="color: #000000;">=</span><span style="color: #000000;"> [</span><span style="color: #000000;">1</span><span style="color: #000000;">, </span><span style="color: #000000;">2</span><span style="color: #000000;">]<br/>i </span><span style="color: #000000;">=</span><span style="color: #000000;"> iter(l)<br/>i.</span>__next__<span style="color: #000000;">()</span><span class="comment"> # 1</span><br/>i.</span>__next__<span style="color: #000000;">()</span><span class="comment"> # 2</span><br/><span style="color: #000000;">l.append(</span><span style="color: #000000;">3</span><span style="color: #000000;">)</span><span class="comment">&nbsp; # Добавим в конец списка ещё один элемент</span><br/>i.</span>__next__<span style="color: #000000;">()</span><span class="comment"> # Без ошибок появилось число 3</span><br/>
				</code>
			</p>
			<h3>Генераторы</h3>
			<p>
				<b>Генераторы</b> - это еще одно понятие функционального программирования, которое очень тесно связано с итераторами. <span class="important" title="Определение">Генераторы - это объекты, которые сохраняют свое состояние между обращениями к ним</span>. 
			</p>
			<p>
				Если говорить о Python'е, то в качестве генераторов выступают функции (объекты). Когда к такой функции обращаются, она возвращает результат и "замирает". Когда к ней обращаются в следующий раз, она продолжает свое выполнение с точки, где остановила свою работу в прошлый раз, а это значит, что все локальные данные были сохранены (например, значения переменных).
			</p>
			<div class="note">
				<p>
					<span class="important">Чаще всего генераторы используются для создания большого объема данных</span>. Простейший пример: нужно обработать огромный массив из элементов, созданных по определенным правилам. Если создать такой список, то он может просто не поместиться в памяти компьютера. Воспользоваться циклами может и не получится - если возникнет необходимость изменить способ обработки (например, на основании обрабатываемых данных), то придется прерывать итерации, а потом начинать сначала, или хранить в цикле кучу переменных нужных для обработки. Генератор же, в свою очередь, будет последовательно отдавать на обработку каждый новый элемент этого списка.
				</p>
			</div>
			<p>
				<span class="important">Генератор создается с помощью ключевого слова <cite>yield</cite> <u>в теле функции</u></span>. <cite>yield</cite> - это <cite>return</cite>, который сохраняет состояние функции и запоминает место выхода из функции. Если после <cite>yield</cite> ничего не указывать, то как и при пустом <cite>return</cite>'е функция вернет <cite>None</cite>. Следующий пример показывает, как можно сделать генератор для множества чисел Фибоначчи:
				<code>
					<span style="color: #0000FF;">def</span><span style="color: #000000;"> Fib(n) :<br/>&nbsp;&nbsp;&nbsp;&nbsp;a, b </span><span style="color: #000000;">=</span><span style="color: #000000;"> 0, </span><span style="color: #000000;">1</span><span style="color: #000000;"><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Начальное значение</span><br/>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF;">for</span><span style="color: #000000;"> i </span><span style="color: #0000FF;">in</span><span style="color: #000000;"> range(n) :<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF;">yield</span><span style="color: #000000;"> a<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a, b </span><span style="color: #000000;">=</span><span style="color: #000000;"> b, a </span><span style="color: #000000;">+</span><span style="color: #000000;"> b</span><span class="comment"> # Вычисление следующего значения</span><br/><br/><span style="color: #0000FF;">for</span><span style="color: #000000;"> i </span><span style="color: #0000FF;">in</span><span style="color: #000000;"> Fib(</span><span style="color: #000000;">100</span><span style="color: #000000;">) :<br/>&nbsp;&nbsp;&nbsp;&nbsp;</span>print<span style="color: #000000;">(i)</span>
				</code>
			</p>
			<p>
				Функция <cite>Fib(100)</cite> вернёт итератор, который будет использоваться в цикле <cite>for</cite>. Каждая итерация генерирует следующее значение (помните, что они все не хранятся в памяти, как в случае со списком или строкой). <span class="important">Инструкция <cite>yield</cite> возвращает сгенерированное значение и запоминает место, на котором она остановила работу генератора</span>. После следующей итерации внешнего цикла мы вернёмся в тело цикла функции <cite>Fib(n)</cite>, где сначала вычислим новые значения для <cite>a</cite> и <cite>b</cite> и перейдём к заголовку внутреннего цикла. И так далее.
			</p>
			<h3>Списковые включения. Генераторы списков</h3>
			<p>
				<b>Списковые включения</b> появились в языке Python, начиная с релиза 2-й версии. <span class="important">Они были введены специально для более естественной записи обработки последовательностей</span>. Можно сказать, что это сокращённый вариант для вложенных циклов и оператора ветвления.
			</p>
			<p>
				Списковые включения <u>упрощают</u> создание новых списков на основе уже имеющихся:
				<code>
					<span style="color: #000000;">source = [1, 2, 3, 4, 5, 6, 7]</span><br/><span class="comment"># Мы хотим умножить каждый элемент на 3 и получить новый список:</span><br/><span style="color: #000000;">result = []</span><br/><span style="color: #0000FF;">for</span><span style="color: #000000;"> elem </span><span style="color: #0000FF;">in</span><span style="color: #000000;"> source :<br/>&nbsp;&nbsp;&nbsp;&nbsp;result.append(elem </span><span style="color: #000000;">*</span><span style="color: #000000;"> </span><span style="color: #000000;">3</span><span style="color: #000000;">)</span><br/><br/>print<span style="color: #000000;">(result)</span><span class="comment"> # [3, 6, 9, 12, 15, 18, 21]</span><br/><br/><span class="comment"># Это можно сделать проще с помощью списковых включений:</span><br/><span style="color: #000000;">result </span><span style="color: #000000;">=</span><span style="color: #000000;"> [elem </span><span style="color: #000000;">*</span><span style="color: #000000;"> </span><span style="color: #000000;">3</span><span style="color: #000000;"> </span><span style="color: #0000FF;">for</span><span style="color: #000000;"> elem </span><span style="color: #0000FF;">in</span><span style="color: #000000;"> source]<br/></span>print<span style="color: #000000;">(result)</span><span class="comment"> # [3, 6, 9, 12, 15, 18, 21]</span>
				</code>
			</p>
			<p>
				Как видите, вместо нескольких строк кода, можно было бы воспользоваться одной и получить нужный результат.
			</p>
			<p>
				Списковые включения состоят из квадратных скобок <cite>[</cite> и <cite>]</cite>, которые содержат выражение (в нашем случае - <cite>elem * 3</cite>), за которым следует цикл <cite>for</cite>. За ним могут следовать другие циклы <cite>for</cite> или операторы <cite>if</cite>. Результатом будет список, состоящих из вычислений выражения в контексте <cite>for</cite>'а и <cite>if</cite>'а стоящих за ним.
			</p>
			<p>
				В выражении не обязательно производить только математические операции, можно вообще ничего не считать или же поставить что-нибудь более сложное:
				<code>
					<span style="color: #000000;">[None </span><span style="color: #0000FF;">for</span><span style="color: #000000;"> i </span><span style="color: #0000FF;">for</span><span style="color: #000000;"> </span><span style="color: #0000FF;">in</span><span style="color: #000000;"> source]<span class="comment"> # Аналог [None] * len(source)</span><br/>[ [elem, elem </span><span style="color: #000000;">**</span><span style="color: #000000;"> </span><span style="color: #000000;">2</span><span style="color: #000000;">] </span><span style="color: #0000FF;">for</span><span style="color: #000000;"> elem </span><span style="color: #0000FF;">in</span><span style="color: #000000;"> source]</span><br/><span class="comment"># [ [1, 1], [2, 4], [3, 9], [4, 16], [5, 25], [6, 36], [7, 49]]</span>
				</code>
			</p>
			<p>
				Можно использовать даже методы объектов:
				<code>
					<span style="color: #000000;">sourceStr </span><span style="color: #000000;">=</span><span style="color: #000000;"> ['&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;banana&nbsp;', '&nbsp;&nbsp;loganberry&nbsp;&nbsp;', 'passion fruit&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;']<br/>result </span><span style="color: #000000;">=</span><span style="color: #000000;"> [elem.strip() </span><span style="color: #0000FF;">for</span><span style="color: #000000;"> elem </span><span style="color: #0000FF;">in</span><span style="color: #000000;"> sourceStr]<br/></span>print<span style="color: #000000;">(result)<span class="comment"> # ['banana', 'loganberry', 'passion fruit']</span>
				</code>
			</p>
			<p>
				С помощью оператора <cite>if</cite> можно фильтровать последовательность:
				<code>
					<span style="color: #000000;">[elem </span><span style="color: #0000FF;">for</span><span style="color: #000000;"> elem </span><span style="color: #0000FF;">in</span><span style="color: #000000;"> source </span><span style="color: #0000FF;">if</span><span style="color: #000000;"> elem </span><span style="color: #000000;">&gt;</span><span style="color: #000000;"> </span><span style="color: #000000;">2</span><span style="color: #000000;">]<span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # [3, 4, 5, 6, 7]</span><br/>[elem </span><span style="color: #0000FF;">for</span><span style="color: #000000;"> elem </span><span style="color: #0000FF;">in</span><span style="color: #000000;"> source </span><span style="color: #0000FF;">if</span><span style="color: #000000;"> </span><span style="color: #0000FF;">not</span><span style="color: #000000;"> elem </span><span style="color: #000000;">%</span><span style="color: #000000;"> </span><span style="color: #000000;">2</span><span style="color: #000000;"> ]</span><span class="comment">&nbsp; # [2, 4 ,6]</span>
				</code>
			</p>
			<p>
				Если выражение должно создавать кортеж, то в объявлении обязательно нужно использовать скобки:
				<code>
					<span style="color: #000000;">[elem, elem </span><span style="color: #000000;">**</span><span style="color: #000000;"> </span><span style="color: #000000;">2</span><span style="color: #000000;"> </span><span style="color: #0000FF;">for</span><span style="color: #000000;"> elem </span><span style="color: #0000FF;">in</span><span style="color: #000000;"> source]</span><span class="error"> # Ошибка</span><br/><br/><span style="color: #000000;">[(elem, elem </span><span style="color: #000000;">**</span><span style="color: #000000;"> </span><span style="color: #000000;">2</span><span style="color: #000000;">) </span><span style="color: #0000FF;">for</span><span style="color: #000000;"> elem </span><span style="color: #0000FF;">in</span><span style="color: #000000;"> source]</span><br/><span class="comment"># [ (1, 1), (2, 4), (3, 9), (4, 16), (5, 25), (6, 36), (7, 49)]</span>
				</code>
			</p>
			<p>
				А вот и примеры вложенных <cite>for</cite>'ов:
				<code>
					<span style="color: #000000;">vec1 = [2, 4, 6]<br/>vec2 = [4, 3, -9]</span><br/><br/><span style="color: #000000;">[x </span><span style="color: #000000;">*</span><span style="color: #000000;"> y </span><span style="color: #0000FF;">for</span><span style="color: #000000;"> x </span><span style="color: #0000FF;">in</span><span style="color: #000000;"> vec1 </span><span style="color: #0000FF;">for</span><span style="color: #000000;"> y </span><span style="color: #0000FF;">in</span><span style="color: #000000;"> vec2]</span><br/><span class="comment"># [8, 6, -18, 16, 12, -36, 24, 18, -54]</span><br/><br/><span style="color: #000000;">[x </span><span style="color: #000000;">+</span><span style="color: #000000;"> y </span><span style="color: #0000FF;">for</span><span style="color: #000000;"> x </span><span style="color: #0000FF;">in</span><span style="color: #000000;"> vec1 </span><span style="color: #0000FF;">for</span><span style="color: #000000;"> y </span><span style="color: #0000FF;">in</span><span style="color: #000000;"> vec2]</span><br/><span class="comment"># [6, 5, -7, 8, 7, -5, 10, 9, -3]</span><br/><br/><span style="color: #000000;">[vec1[i] </span><span style="color: #000000;">*</span><span style="color: #000000;"> vec2[i] </span><span style="color: #0000FF;">for</span><span style="color: #000000;"> i </span><span style="color: #0000FF;">in</span><span style="color: #000000;"> range(len(vec1))]</span><br/><span class="comment"># [8, 12, -54]</span>
				</code>
			</p>
			<p>
				Списковые включения всегда возвращают уже готовый список. Но если нет необходимости иметь весь список, то можно создать генератор. Делается это очень просто - вместо квадратных скобок <cite>[</cite> и <cite>]</cite> нужно написать круглые <cite>(</cite> и <cite>)</cite>:
				<code>
					<span style="color: #000000;">l </span><span style="color: #000000;">=</span><span style="color: #000000;"> [elem </span><span style="color: #0000FF;">for</span><span style="color: #000000;"> elem </span><span style="color: #0000FF;">in</span><span style="color: #000000;"> source </span><span style="color: #0000FF;">if</span><span style="color: #000000;"> </span><span style="color: #0000FF;">not</span><span style="color: #000000;"> elem </span><span style="color: #000000;">%</span><span style="color: #000000;"> </span><span style="color: #000000;">2</span><span style="color: #000000;"> ]</span><br/>print<span style="color: #000000;">(type(l))</span><span class="comment"> # &lt;class 'list'&gt;</span><br/>print<span style="color: #000000;">(l)</span><span class="comment"> # [2, 4, 6]</span><br/><br/><span style="color: #000000;">g </span><span style="color: #000000;">=</span><span style="color: #000000;"> (elem </span><span style="color: #0000FF;">for</span><span style="color: #000000;"> elem </span><span style="color: #0000FF;">in</span><span style="color: #000000;"> source </span><span style="color: #0000FF;">if</span><span style="color: #000000;"> </span><span style="color: #0000FF;">not</span><span style="color: #000000;"> elem </span><span style="color: #000000;">%</span><span style="color: #000000;"> </span><span style="color: #000000;">2</span><span style="color: #000000;"> )</span><br/>print<span style="color: #000000;">(type(g))</span><span class="comment"> # &lt;class 'generator'></span><br/>print<span style="color: #000000;">(g)</span><span class="comment"> # &lt;generator object &lt;genexpr> at 0xb748f9dc></span><br/>print<span style="color: #000000;">(g.__next__())</span><span class="comment"> # 2</span><br/>print<span style="color: #000000;">(g.__next__())</span><span class="comment"> # 4</span><br/>print<span style="color: #000000;">(g.__next__())</span><span class="comment"> # 6</span><br/>
				</code>
			</p>
			<hr/>
			<p>
				В заключении данной темы хочется напомнить вам, что Python является в большей степени объектно-ориентированным языком, а функциональные возможности, которые он предоставляет, в некоторых случаях облегчают написание кода, его понимание и дальнейшую поддержку.
			</p>
		</div>
		<div class="footer"></div>
	</body>
</html>